package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.MapUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutomaticReviewService;
import com.mysql.jdbc.StringUtils;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import javax.rmi.CORBA.Tie;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ybw
 * @version 1.0
 * @date 2021/12/14 21:19
 */
@Service
@Slf4j
@Transactional
public class WmNewsAutomaticReviewServiceImpl implements WmNewsAutomaticReviewService {
  @Autowired private WmNewsMapper wmNewsMapper;
  @Autowired private IArticleClient iArticleClient;
  @Autowired private WmUserMapper wmUserMapper;
  @Autowired private WmChannelMapper wmChannelMapper;
  @Autowired private GreenTextScan greenTextScan;
  @Autowired private GreenImageScan greenImageScan;
  @Autowired private FileStorageService fileStorageService;
  @Autowired private WmSensitiveMapper wmSensitiveMapper;
  @Autowired private Tess4jClient tess4jClient;

  /**
   * 自媒体文章自动审核
   *
   * @param id 文章id
   */
  @Override
  @Async
  public ResponseResult newsAutomaticReview(Integer id) {
    // 参数校验
    if (id == null) {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "id不能为空");
    }
    // 根据文章id查询文章内容
    WmNews wmNews = wmNewsMapper.selectById(id);
    if (wmNews == null) {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "未查询到文章");
    }
    // 获取文章状态
    Short status = wmNews.getStatus();
    if (status == 1) {
      // 待审核状态
      // 抽取文本和图片
      Map map = extractTextAndImg(wmNews);
      // 自管理的敏感词过滤
      boolean isSensitive = handleSensitiveScan((String) map.get("content"), wmNews);
      if (!isSensitive) {
        return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_IMAGE_FORMAT_ERROR, "文本审核失败");
      }
      // 审核文本
      boolean textFlag = scanText(wmNews, (String) map.get("content"));
      if (!textFlag) {
        return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_IMAGE_FORMAT_ERROR, "文本审核失败");
      }
      // 审核图片
      boolean imgFlag = scanImg(wmNews, (List<String>) map.get("images"));
      if (!imgFlag) {
        return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_IMAGE_FORMAT_ERROR, "文本审核失败");
      }
      // 审核成功
      // 保存app文章
      ResponseResult result = saveAppArticle(wmNews);
      if (result.getCode() != 200) {
        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "远程调用iArticleClient接口失败");
      }
      // app文章保存之后会返回文章id
      Long articleId = (Long) result.getData();
      wmNews.setArticleId(articleId);
      // 将文章id保存进文章信息表，更新文章状态
      updateNews(wmNews, (short) 9, "审核成功");
      return ResponseResult.okResult(200, "审核成功");
    } else {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }
  }

  /**
   * 自助敏感词过滤
   *
   * @param content
   * @param wmNews
   * @return
   */
  private boolean handleSensitiveScan(String content, WmNews wmNews) {
    boolean flag = true;

    // 获取所有的敏感词
    List<WmSensitive> wmSensitives =
        wmSensitiveMapper.selectList(
            Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
    List<String> sensitiveList =
        wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

    // 初始化敏感词库
    SensitiveWordUtil.initMap(sensitiveList);

    // 查看文章中是否包含敏感词
    Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
    if (map.size() > 0) {
      updateNews(wmNews, (short) 2, "当前文章中存在违规内容" + map);
      flag = false;
    }

    return flag;
  }

  /**
   * 抽取文本和图片内容
   *
   * @param wmNews
   */
  private Map extractTextAndImg(WmNews wmNews) {
    // 获取文章内容
    String content = wmNews.getContent();
    // 转换为map
    List<Map> maps = JSON.parseArray(content, Map.class);
    Map<String, Object> retMap = new HashMap();
    ArrayList<String> imgArr = new ArrayList<>();
    StringBuilder sb = new StringBuilder();
    for (Map map : maps) {
      if ("text".equals(map.get("type"))) {
        // 文本
        Object text = map.get("value");
        sb.append(text.toString());
      } else if ("image".equals(map.get("type"))) {
        // 图片
        Object image = map.get("value");
        imgArr.add(image.toString());
      }
    }
    // 标题
    sb.append(wmNews.getTitle());
    // 封面
    if (wmNews.getImages() != null) {
      List<String> collect =
          Arrays.stream(wmNews.getImages().split(",")).collect(Collectors.toList());
      imgArr.addAll(collect);
    }

    retMap.put("content", sb.toString());
    retMap.put("images", imgArr);
    return retMap;
  }

  /**
   * 图片审核
   *
   * @param wmNews
   * @param images
   * @return
   */
  private boolean scanImg(WmNews wmNews, List<String> images) {
    ArrayList<byte[]> byts = new ArrayList<>();
    short status = 4;
    String reason = "审核成功";
    boolean flag = true;
    if (CollectionUtils.isNotEmpty(images)) {
      // 图片去重
      List<String> collect = images.stream().distinct().collect(Collectors.toList());
      // 图片下载
      try {
        for (String image : collect) {
          byte[] bytes = fileStorageService.downLoadFile(image);

          // 图片识别文字审核---begin-----
          // 从byte[]转换为butteredImage
          ByteArrayInputStream in = new ByteArrayInputStream(bytes);
          BufferedImage imageFile = ImageIO.read(in);
          // 识别图片的文字
          String result = tess4jClient.doOCR(imageFile);
          // 审核是否包含自管理的敏感词
          boolean isSensitive = handleSensitiveScan(result, wmNews);
          if (!isSensitive) {
            return isSensitive;
          }
          // 图片识别文字审核---end-----

          byts.add(bytes);
        }

        Map map = greenImageScan.imageScan(byts);
        String suggestion = "";
        if (MapUtils.isNotEmpty(map)) {
          suggestion = (String) map.get("suggestion");
          if ("block".equals(suggestion)) {
            // 审核失败
            // 修改数据库状态
            status = 2;
            reason = "图片审核失败";
            flag = false;
          } else if ("review".equals(suggestion)) {
            // 审核失败
            // 修改数据库状态
            status = 3;
            reason = "图片人工审核";
            flag = false;
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
        // 审核失败
        // 修改数据库状态
        status = 2;
        reason = "图片审核失败";
        flag = false;
      }
    }
    updateNews(wmNews, status, reason);
    return flag;
  }

  /**
   * 文本审核
   *
   * @param wmNews
   * @param content 统计之后的文本内容
   * @return
   */
  private boolean scanText(WmNews wmNews, String content) {
    short status = 4;
    String reason = "审核成功";
    boolean flag = true;
    try {
      Map map = greenTextScan.greeTextScan(content);
      String suggestion = "";
      if (MapUtils.isNotEmpty(map)) {
        suggestion = (String) map.get("suggestion");
        if ("block".equals(suggestion)) {
          // 审核失败
          // 修改数据库状态
          status = 2;
          reason = "文本审核失败";
          flag = false;
        } else if ("review".equals(suggestion)) {
          // 审核失败
          // 修改数据库状态
          status = 3;
          reason = "文本人工审核";
          flag = false;
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      // 审核失败
      // 修改数据库状态
      status = 2;
      reason = "文本审核失败";
      flag = false;
    }
    updateNews(wmNews, status, reason);
    return flag;
  }

  /**
   * 保存app文章
   *
   * @param wmNews
   * @return
   */
  private ResponseResult saveAppArticle(WmNews wmNews) {
    // 根据作者id查询用户
    WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
    // 根据id查询频道
    WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
    // 初始化dto
    ArticleDto articleDto = ArticleDto.init(wmUser, wmNews, wmChannel);

    // 远程调用接口，保存文章article/article_config/article_content
    ResponseResult result = iArticleClient.saveArticle(articleDto);
    return result;
  }

  /**
   * 更新文章状态
   *
   * @param wmNews
   * @param status
   * @param reason
   */
  private void updateNews(WmNews wmNews, short status, String reason) {
    wmNews.setStatus(status);
    wmNews.setReason(reason);
    wmNewsMapper.updateById(wmNews);
  }
}
